// Yang Shuai  Copyright (c) 2022 https://yby6.com.
// Copyright (c) 2022. Yangbuyi, personal projects are not allowed to be commercialized without permission.
// Please keep the information of the original author of the code. Thank you
//

package top.yangbuyi.service_pay.controller;

import com.google.gson.Gson;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import top.yangbuyi.common_utils.utils.GsonUtils;
import top.yangbuyi.common_utils.utils.HttpUtils;
import top.yangbuyi.common_utils.utils.ResponseResult;
import top.yangbuyi.service_pay.common.config.WechatPay2ValidatorForRequest;
import top.yangbuyi.service_pay.entity.TradeBillResponse;
import top.yangbuyi.service_pay.service.WxPayService;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

/**
 * 网站微信支付APIv3
 *
 * <pre>
 *     RequestMapping 如需更改此参数 请修改WxNotifyType当中对应的前缀
 * </pre>
 *
 * <p>
 *     注意: 方法头部加了@Deprecated此注解表示不可使用 该支付系统完整DEMO在
 *     <a href="https://gitee.com/yby6/yangbuyi-rbac/tree/master/yangbuyi-rbac/yangbuyi-wxpay">yangbuyi-wxpay</a>
 * </p>
 *
 */
@RestController
@RequestMapping("/service_pay/wx-pay")
@Api(tags = "网站微信支付APIv3")
@Slf4j
public class WxPayController {

    @Resource
    private WxPayService wxPayService;

    @Resource
    private Verifier verifier;


    @ApiOperation("调用统一下单API，生成支付二维码")
    @PostMapping("/native/{contentId}")
    public ResponseResult nativePay(@PathVariable Long contentId, HttpServletRequest request) {
        log.info("发起支付请求 v3, 返回支付二维码连接和订单号");
        try {
            return ResponseResult.toOk(wxPayService.nativePay(contentId));
        } catch (Exception e) {
            log.error("创建用户订单失败: {0}", e);
            return ResponseResult.error("创建用户订单失败");
        }
    }

    @ApiOperation("支付通知->微信支付通过支付通知接口将用户支付成功消息通知给商户")
    @PostMapping("/native/notify")
    public String nativeNotify(HttpServletRequest request, HttpServletResponse response) {
        log.info("接收到微信服务回调......");
        Map<String, String> map = new HashMap<>();// 应答对象，给微信服务答复是否通知成功

        try {
            //处理通知参数
            String body = HttpUtils.readData(request);
            log.info("微信回调参数：{}", body);
            Map<String, Object> bodyMap = GsonUtils.toObject(body, HashMap.class);
            String requestId = (String) bodyMap.get("id");
            log.info("支付通知的id ===> {}", requestId);

            //签名的验证
            WechatPay2ValidatorForRequest wechatPay2ValidatorForRequest = new WechatPay2ValidatorForRequest(verifier, requestId, body);
            if (!wechatPay2ValidatorForRequest.validate(request)) {
                log.error("通知验签失败");
                //失败应答
                response.setStatus(500);
                map.put("code", "ERROR");
                map.put("message", "通知验签失败");
                return GsonUtils.toJsonStr(map);
            }
            log.info("通知验签成功");

            // 处理订单
            wxPayService.processOrder(bodyMap);
            log.info("回调业务处理完毕");
            // 成功应答
            response.setStatus(200);
            map.put("code", "SUCCESS");
            map.put("message", "成功");
            return GsonUtils.toJsonStr(map);
        } catch (Exception e) {
            e.printStackTrace();
            //失败应答
            response.setStatus(500);
            map.put("code", "FAIL");
            map.put("message", "失败");
            return GsonUtils.toJsonStr(map);
        }

    }


    /**
     * 查询订单
     */
    @ApiOperation("查询订单：测试订单状态用")
    @GetMapping("/query/{orderNo}")
    public ResponseResult queryOrder(@PathVariable String orderNo) throws Exception {

        log.info("查询订单");

        return ResponseResult.toOk(wxPayService.queryOrder(orderNo));

    }

    /**
     * 用户取消订单
     */
    @ApiOperation("用户取消订单")
    @PostMapping("/cancel/{orderNo}")
    public ResponseResult cancel(@PathVariable String orderNo) throws Exception {
        log.info("取消订单");
        wxPayService.cancelOrder(orderNo);
        return ResponseResult.toOk("订单已取消");
    }

    /**
     * 申请退款
     * @param orderNo 订单编号
     * @param refundsNo 退款单号后四位（交易订单编号）
     * @param reason 退款描述
     */
    @ApiOperation("申请退款")
    @PostMapping("/refunds/{orderNo}/{refundsNo}/{reason}")
    public ResponseResult refunds(@PathVariable String orderNo, @PathVariable String refundsNo, @PathVariable String reason) throws Exception {
        log.info("申请退款");
        wxPayService.refund(orderNo, reason, refundsNo);
        return ResponseResult.ok();
    }

    /**
     * 查询退款
     */
    @ApiOperation("查询退款：测试用")
    @GetMapping("/query-refund/{refundNo}")
    public ResponseResult queryRefund(@PathVariable String refundNo) throws Exception {

        log.info("查询退款");

        String result = wxPayService.queryRefund(refundNo);
        return ResponseResult.toOk(result);
    }

    /**
     * 退款结果通知
     * 退款状态改变后，微信会把相关退款结果发送给商户。
     */
    @ApiOperation("退款结果通知")
    @PostMapping("/refunds/notify")
    public String refundsNotify(HttpServletRequest request, HttpServletResponse response) {

        log.info("退款通知执行");

        Gson gson = new Gson();
        Map<String, String> map = new HashMap<>();// 应答对象

        try {
            //处理通知参数
            String body = HttpUtils.readData(request);
            Map<String, Object> bodyMap = gson.fromJson(body, HashMap.class);
            log.info("退款参数：{}", bodyMap);
            String requestId = (String) bodyMap.get("id");
            log.info("支付通知的id ===> {}", requestId);

            //签名的验证
            WechatPay2ValidatorForRequest wechatPay2ValidatorForRequest = new WechatPay2ValidatorForRequest(verifier, requestId, body);
            if (!wechatPay2ValidatorForRequest.validate(request)) {

                log.error("通知验签失败");
                //失败应答
                response.setStatus(500);
                map.put("code", "ERROR");
                map.put("message", "通知验签失败");
                return gson.toJson(map);
            }
            log.info("通知验签成功");

            // 处理退款单
            wxPayService.processRefund(bodyMap);

            // 成功应答
            response.setStatus(200);
            map.put("code", "SUCCESS");
            map.put("message", "成功");
            return gson.toJson(map);
        } catch (Exception e) {
            e.printStackTrace();
            //失败应答
            response.setStatus(500);
            map.put("code", "ERROR");
            map.put("message", "失败");
            return gson.toJson(map);
        }
    }

    /**
     * 申请交易账单API
     *
     * @param billDate 账单日期 格式yyyy-MM-dd 仅支持三个月内的账单下载申请
     * @param type     账单类型 不填则默认是ALL
     *                 ALL：返回当日所有订单信息（不含充值退款订单）
     *                 SUCCESS：返回当日成功支付的订单（不含充值退款订单）
     *                 REFUND：返回当日退款订单（不含充值退款订单）
     */
    @ApiOperation("获取账单url：测试用")
    @GetMapping("/querybill/{billDate}/{type}")
    public ResponseResult queryTradeBill(@PathVariable String billDate, @PathVariable String type) throws Exception {

        log.info("获取账单url");

        TradeBillResponse tradeBillResponse = wxPayService.queryBill(billDate, type);

        return ResponseResult.ok().data("downloadUrl", tradeBillResponse.getDownload_url()).data("tradeBillResponse", tradeBillResponse);
    }

    @ApiOperation("下载账单")
    @GetMapping("/downloadbill/{billDate}/{type}")
    public ResponseResult downloadBill(@PathVariable String billDate, @PathVariable String type) throws Exception {

        log.info("下载账单");
        String result = wxPayService.downloadBill(billDate, type);

        return ResponseResult.toOk(result);
    }

}
